package com.xiezc.springboot_dht.message;

import com.xiezc.springboot_dht.model.BeMap;
import com.xiezc.springboot_dht.model.BeObject;
import com.xiezc.springboot_dht.model.BeString;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Objects;
import java.util.Set;

/**
 * @author wb-xzc291800
 * @date 2018/05/11 15:27
 */
@Slf4j
public class MessageBuild {

    static BeString r = new BeString("r");
    static BeString t = new BeString("t");
    static BeString a = new BeString("a");
    static BeString y = new BeString("y");
    static BeString q = new BeString("q");
    static BeString ping = new BeString("ping");
    static BeString find_node = new BeString("find_node");
    static BeString get_peers = new BeString("get_peers");
    static BeString annountce_peer = new BeString("annountce_peer");
    static BeString id = new BeString("id");
    static BeString info_hash = new BeString("info_hash");
    static BeString target = new BeString("target");
    static BeString port = new BeString("port");
    static BeString implied_port = new BeString("implied_port");
    static BeString token = new BeString("token");
    static BeString nodes = new BeString("nodes");
    static BeString values = new BeString("values");

    /**
     * 构建请求消息
     *
     * @return
     */
    public static ReqMsgBuild buildReqMsg() {
        BeMap beMap = new BeMap();
        beMap.put(y, q);
        return new ReqMsgBuild(beMap);
    }

    /**
     * 获得相应消息, 并判断相应消息的类型,
     * <p>
     * 判断响应消息类型的方式是: 根据t字段来判断, t字段是回显请求消息的字段
     *
     * @param beMap
     * @param socketAddress
     * @return
     */
    public static Message buildMsg(BeMap beMap, InetSocketAddress socketAddress) {
        BeObject beObject = beMap.get(y);

        BeString tBs = (BeString) beMap.get(t);
        if (tBs == null) {
            log.error("接收到的消息的格式不对，没有ｔ字段");
            log.error(beMap.toString());
            return null;
        }

        if (Objects.equals(beObject, r)) {
            BeObject beObject1 = beMap.get(r);
            if (beObject1 == null || !(beObject1 instanceof BeMap)) {
                return null;
            }
            BeMap r = (BeMap) beObject1;
            Set<BeObject> beObjects = r.getValue().keySet();

            char tf = (char) tBs.getValue()[0];

            boolean hasId = beObjects.contains(id);
            boolean hasNodes = beObjects.contains(nodes);
            boolean hasToken = beObjects.contains(token);
            boolean hasValues = beObjects.contains(values);

            if (tf == 'p' && hasId) {
                Message message = new Message();
                message.setBeMap(beMap);
                message.setMsgTypeEnum(MsgTypeEnum.resp_ping);
                message.setSocketAddress(socketAddress);
                return message;
            } else if (tf == 'f' && hasId && hasNodes) {
                Message message = new Message();
                message.setBeMap(beMap);
                message.setMsgTypeEnum(MsgTypeEnum.resp_findNode);
                message.setSocketAddress(socketAddress);
                return message;
            } else if (tf == 'g' && hasId && hasToken && (hasNodes || hasValues)) {
                Message message = new Message();
                message.setBeMap(beMap);
                if (hasNodes) {
                    message.setMsgTypeEnum(MsgTypeEnum.resp_getPeers);
                } else if (hasValues) {
                    message.setMsgTypeEnum(MsgTypeEnum.resp_getPeersVal);
                }
                message.setSocketAddress(socketAddress);
                return message;
            } else if (tf == 'a' && hasId) {
                log.warn("收到了annountce_peer消息的回复, 不可能的事情, 所以丢弃这个有问题的消息, 不处理");
            } else {
                log.warn("响应消息解析不对, 所以也是丢弃消息", beMap.toString());
            }
        } else if (Objects.equals(beObject, q)) {
            BeString beString = (BeString) beMap.get(q);
            if (Objects.equals(beString, ping)) {
                Message message = new Message();
                message.setBeMap(beMap);
                message.setMsgTypeEnum(MsgTypeEnum.ping);
                message.setSocketAddress(socketAddress);
                return message;
            } else if (Objects.equals(beString, find_node)) {
                Message message = new Message();
                message.setBeMap(beMap);
                message.setMsgTypeEnum(MsgTypeEnum.findNode);
                message.setSocketAddress(socketAddress);
                return message;
            } else if (Objects.equals(beString, get_peers)) {
                Message message = new Message();
                message.setBeMap(beMap);
                message.setMsgTypeEnum(MsgTypeEnum.getPeers);
                message.setSocketAddress(socketAddress);
                return message;
            } else if (Objects.equals(beString, annountce_peer)) {
                Message message = new Message();
                message.setBeMap(beMap);
                message.setMsgTypeEnum(MsgTypeEnum.annountcePeer);
                message.setSocketAddress(socketAddress);
                return message;
            } else {
                log.error("接收到的消息虽然是请求消息，ｑ字段是：{}",beString.toString());
            }
        } else {
            log.error("接收到消息的Ｙ字段不符合要求是：{}", beObject.toString());
        }

        return null;
    }

    /**
     * 构建效应消息
     *
     * @return
     */
    public static RespMsgBuild buildRespMsg() {
        BeMap beMap = new BeMap();
        beMap.put(y, r);
        return new RespMsgBuild(beMap);
    }

}
